package com.gitee.wsl.ext.string

import com.gitee.wsl.ext.base.SPACE
import com.gitee.wsl.ext.string.DesensitizedUtil.DesensitizedType
import com.gitee.wsl.ext.string.DesensitizedUtil.address
import com.gitee.wsl.ext.string.DesensitizedUtil.carLicense
import com.gitee.wsl.ext.string.DesensitizedUtil.email
import com.gitee.wsl.ext.string.DesensitizedUtil.idCardNum
import com.gitee.wsl.ext.string.DesensitizedUtil.ipv4
import com.gitee.wsl.ext.string.DesensitizedUtil.ipv6
import com.gitee.wsl.ext.string.DesensitizedUtil.password


/**
 * 脱敏工具类，支持以下类型信息的脱敏自动处理：
 *
 *
 *  * 用户ID
 *  * 中文名
 *  * 身份证
 *  * 座机号
 *  * 手机号
 *  * 地址
 *  * 电子邮件
 *  * 密码
 *  * 车牌
 *  * 银行卡号
 *
 *
 * @author dazer and neusoft and qiaomu
 * @since 5.6.2
 */
object DesensitizedUtil {
    /**
     * 脱敏，使用默认的脱敏策略
     * <pre>
     * DesensitizedUtil.desensitized("100", DesensitizedUtil.DesensitizedType.USER_ID)) =  "0"
     * DesensitizedUtil.desensitized("段正淳", DesensitizedUtil.DesensitizedType.CHINESE_NAME)) = "段**"
     * DesensitizedUtil.desensitized("51343620000320711X", DesensitizedUtil.DesensitizedType.ID_CARD)) = "5***************1X"
     * DesensitizedUtil.desensitized("09157518479", DesensitizedUtil.DesensitizedType.FIXED_PHONE)) = "0915*****79"
     * DesensitizedUtil.desensitized("18049531999", DesensitizedUtil.DesensitizedType.MOBILE_PHONE)) = "180****1999"
     * DesensitizedUtil.desensitized("北京市海淀区马连洼街道289号", DesensitizedUtil.DesensitizedType.ADDRESS)) = "北京市海淀区马********"
     * DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtil.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn"
     * DesensitizedUtil.desensitized("1234567890", DesensitizedUtil.DesensitizedType.PASSWORD)) = "**********"
     * DesensitizedUtil.desensitized("苏D40000", DesensitizedUtil.DesensitizedType.CAR_LICENSE)) = "苏D4***0"
     * DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtil.DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256"
     * DesensitizedUtil.desensitized("192.168.1.1", DesensitizedUtil.DesensitizedType.IPV4)) = "192.*.*.*"
    </pre> *
     *
     * @param str              字符串
     * @param desensitizedType 脱敏类型;可以脱敏：用户id、中文名、身份证号、座机号、手机号、地址、电子邮件、密码
     * @return 脱敏之后的字符串
     * @author dazer and neusoft and qiaomu
     * @since 5.6.2
     */
    fun desensitized(str: CharSequence?, desensitizedType: DesensitizedType): String {
        if (str.isNullOrBlank()) {
           return String.EMPTY
        }

       return when (desensitizedType) {
            DesensitizedType.USER_ID ->  userId().toString()
            DesensitizedType.CHINESE_NAME ->  chineseName(str.toString())
            DesensitizedType.ID_CARD ->  idCardNum(str.toString(), 1, 2)
            DesensitizedType.FIXED_PHONE ->  fixedPhone(str.toString())
            DesensitizedType.MOBILE_PHONE ->  mobilePhone(str.toString())
            DesensitizedType.ADDRESS ->  address(str.toString(), 8)
            DesensitizedType.EMAIL ->  email(str.toString())
            DesensitizedType.PASSWORD ->  password(str.toString())
            DesensitizedType.CAR_LICENSE ->  carLicense(str.toString())
            DesensitizedType.BANK_CARD ->  bankCard(str.toString())
            DesensitizedType.IPV4 ->  ipv4(str.toString())
            DesensitizedType.IPV6 ->  ipv6(str.toString())
            DesensitizedType.PASSPORT ->  passport(str.toString())
            DesensitizedType.CREDIT_CODE ->  creditCode(str.toString())
            DesensitizedType.FIRST_MASK ->  firstMask(str.toString())
            DesensitizedType.CLEAR_TO_EMPTY ->  clear()
            //DesensitizedType.CLEAR_TO_NULL ->  clearToNull()
        }
    }

    /**
     * 清空为空字符串
     *
     * @return 清空后的值
     * @since 5.8.22
     */
    fun clear(): String {
        return String.EMPTY
    }

    /**
     * 清空为`null`
     *
     * @return 清空后的值(null)
     * @since 5.8.22
     */
//    fun clearToNull(): String {
//        return String.EMPTY
//    }

    /**
     * 【用户id】不对外提供userId
     *
     * @return 脱敏后的主键
     */
    fun userId(): Long {
        return 0L
    }

    /**
     * 定义了一个first_mask的规则，只显示第一个字符。<br></br>
     * 脱敏前：123456789；脱敏后：1********。
     *
     * @param str 字符串
     * @return 脱敏后的字符串
     */
    fun firstMask(str: String): String {
        if (str.isBlank()) {
           return String.EMPTY
        }
        return hide(str, 1, str.length)
    }

    /**
     * 【中文姓名】只显示第一个汉字，其他隐藏为2个星号，比如：李**
     *
     * @param fullName 姓名
     * @return 脱敏后的姓名
     */
    fun chineseName(fullName: String): String {
        return firstMask(fullName)
    }

    /**
     * 【身份证号】前1位 和后2位
     *
     * @param idCardNum 身份证
     * @param front     保留：前面的front位数；从1开始
     * @param end       保留：后面的end位数；从1开始
     * @return 脱敏后的身份证
     */
    fun idCardNum(idCardNum: String, front: Int, end: Int): String {
        //身份证不能为空
        if (idCardNum.isBlank()) {
                return String.EMPTY
        }
        //需要截取的长度不能大于身份证号长度
        if ((front + end) > idCardNum.length) {
            return String.EMPTY
        }
        //需要截取的不能小于0
        if (front < 0 || end < 0) {
            return String.EMPTY
        }
        return hide(idCardNum, front, idCardNum.length - end)
    }

    /**
     * 【固定电话 前四位，后两位
     *
     * @param num 固定电话
     * @return 脱敏后的固定电话；
     */
    fun fixedPhone(num: String): String {
        if (num.isBlank()) {
            return String.EMPTY
        }
        return hide(num, 4, num.length - 2)
    }

    /**
     * 【手机号码】前三位，后4位，其他隐藏，比如135****2210
     *
     * @param num 移动电话；
     * @return 脱敏后的移动电话；
     */
    fun mobilePhone(num: String): String {
        if (num.isBlank()) {
                return String.EMPTY
        }
        return hide(num, 3, num.length - 4)
    }

    /**
     * 【地址】只显示到地区，不显示详细地址，比如：北京市海淀区****
     *
     * @param address       家庭住址
     * @param sensitiveSize 敏感信息长度
     * @return 脱敏后的家庭地址
     */
    fun address(address: String, sensitiveSize: Int): String {
        if (address.isBlank()) {
            return String.EMPTY
        }
        val length = address.length
        return hide(address, length - sensitiveSize, length)
    }

    /**
     * 【电子邮箱】邮箱前缀仅显示第一个字母，前缀其他隐藏，用星号代替，@及后面的地址显示，比如：d**@126.com
     *
     * @param email 邮箱
     * @return 脱敏后的邮箱
     */
    fun email(email: String?): String {
        if (email.isNullOrBlank()) {
            return String.EMPTY
        }
        val index: Int = email.indexOf('@')
        if (index <= 1) {
            return email
        }
        return hide(email, 1, index)
    }

    /**
     * 【密码】密码的全部字符都用*代替，比如：******
     *
     * @param password 密码
     * @return 脱敏后的密码
     */
    fun password(password: String): String {
        if (password.isBlank()) {
            return String.EMPTY
        }
        return '*'.repeat(password.length)
    }

    /**
     * 【中国车牌】车牌中间用*代替
     * eg1：null       -》 ""
     * eg1：""         -》 ""
     * eg3：苏D40000   -》 苏D4***0
     * eg4：陕A12345D  -》 陕A1****D
     * eg5：京A123     -》 京A123     如果是错误的车牌，不处理
     *
     * @param carLicense 完整的车牌号
     * @return 脱敏后的车牌
     */
    fun carLicense(carLicense: String): String {
        var carLicense = carLicense
        if (carLicense.isBlank()) {
            return String.EMPTY
        }
        // 普通车牌
        if (carLicense.length == 7) {
            carLicense = hide(carLicense, 3, 6)
        } else if (carLicense.length == 8) {
            // 新能源车牌
            carLicense = hide(carLicense, 3, 7)
        }
        return carLicense
    }

    /**
     * 【银行卡号脱敏】由于银行卡号长度不定，所以只展示前4位，后面的位数根据卡号决定展示1-4位
     * 例如：
     * <pre>`1. "1234 2222 3333 4444 6789 9"    ->   "1234 **** **** **** **** 9"
     * 2. "1234 2222 3333 4444 6789 91"   ->   "1234 **** **** **** **** 91"
     * 3. "1234 2222 3333 4444 678"       ->    "1234 **** **** **** 678"
     * 4. "1234 2222 3333 4444 6789"      ->    "1234 **** **** **** 6789"
    `</pre> *
     *
     * @param bankCardNo 银行卡号
     * @return 脱敏之后的银行卡号
     */
    fun bankCard(bankCardNo: String): String {
        var bankCardNo = bankCardNo
        if (bankCardNo.isBlank()) {
            return bankCardNo
        }
        bankCardNo = bankCardNo.cleanBlank()
        if (bankCardNo.length < 9) {
            return bankCardNo
        }

        val length = bankCardNo.length
        val endLength = if (length % 4 == 0) 4 else length % 4
        val midLength = length - 4 - endLength

        val buf = StringBuilder()
        buf.append(bankCardNo, 0, 4)
        for (i in 0..<midLength) {
            if (i % 4 == 0) {
                buf.append(Char.SPACE)
            }
            buf.append('*')
        }
        buf.append(Char.SPACE).append(bankCardNo, length - endLength, length)
        return buf.toString()
    }

    /**
     * IPv4脱敏，如：脱敏前：192.0.2.1；脱敏后：192.*.*.*。
     *
     * @param ipv4 IPv4地址
     * @return 脱敏后的地址
     */
    fun ipv4(ipv4: String): String {
        return ipv4.substringBefore('.') + ".*.*.*"
    }

    /**
     * IPv6脱敏，如：脱敏前：2001:0db8:86a3:08d3:1319:8a2e:0370:7344；脱敏后：2001:*:*:*:*:*:*:*
     *
     * @param ipv6 IPv6地址
     * @return 脱敏后的地址
     */
    fun ipv6(ipv6: String): String {
        return ipv6.substringBefore( ':') + ":*:*:*:*:*:*:*"
    }

    /**
     * 护照号脱敏
     * 规则：前2后2，长度不足时保留最小有效信息
     * 示例：PJ1234567 → PJ*****67
     */
    fun passport(passport: String): String {
        if (passport.isBlank()) return passport
        val length = passport.length
        if (length <= 2) return hide(passport, 0, length)
        return hide(passport, 2, length - 2)
    }

    /**
     * 统一社会信用代码脱敏
     * 规则：前4后4，长度不足时保留最小有效信息
     * 统一社会信用代码由18位数字或大写英文字母组成
     * 示例：91110108MA01ABCDE7   → 9111**********CDE7
     *
     */
    fun creditCode(code: String): String {
        if (code.isBlank()) return code
        val length = code.length
        if (length <= 4) return hide(code, 0, length)
        return hide(code, 4, length - 4)
    }

    private fun hide(str: String, startIndex: Int, endIndex: Int): String = str.hide(startIndex,endIndex)


    /**
     * 支持的脱敏类型枚举
     *
     * @author dazer and neusoft and qiaomu
     */
    enum class DesensitizedType {
        /**
         * 用户id
         */
        USER_ID,

        /**
         * 中文名
         */
        CHINESE_NAME,

        /**
         * 身份证号
         */
        ID_CARD,

        /**
         * 座机号
         */
        FIXED_PHONE,

        /**
         * 手机号
         */
        MOBILE_PHONE,

        /**
         * 地址
         */
        ADDRESS,

        /**
         * 电子邮件
         */
        EMAIL,

        /**
         * 密码
         */
        PASSWORD,

        /**
         * 中国大陆车牌，包含普通车辆、新能源车辆
         */
        CAR_LICENSE,

        /**
         * 银行卡
         */
        BANK_CARD,

        /**
         * IPv4地址
         */
        IPV4,

        /**
         * IPv6地址
         */
        IPV6,

        /**
         * 护照号
         */
        PASSPORT,

        /**
         * 统一社会信用代码
         */
        CREDIT_CODE,

        /**
         * 定义了一个first_mask的规则，只显示第一个字符。
         */
        FIRST_MASK,

        /**
         * 清空为null
         */
        //CLEAR_TO_NULL,

        /**
         * 清空为""
         */
        CLEAR_TO_EMPTY
    }
}

fun CharSequence?.desensitized(desensitizedType: DesensitizedType) = DesensitizedUtil.desensitized(this,desensitizedType)